import { useFormStore } from "@/store/form";
import {
  isObject,
  isFunction,
  isTableHelperColumn,
  getFieldDefaultValue,
  genFieldMapField,
} from "@/utils";
import { getFieldConfig } from "@/components/RuntimeComp";
import { isVue3Version } from "../index.js";
import genTokenUtil from "./warpToken";

let fieldConfig = {};

function formItemFactory(formField, store) {
  const globalConfig = store.globalConfig;
  const uiType = store.uiType;
  const wrapReadonlyTokenFlag = store.wrapReadonlyToken;
  const { wrapFormItemToken, wrapReadonlyToken } = genTokenUtil(uiType);
  return {
    generator(needWrapItem = true, needWrapReadonly = wrapReadonlyTokenFlag) {
      const fieldFactory = fieldConfig[formField.type] ?? fieldConfig.input;
      let str = fieldFactory.code(
        formField,
        globalConfig,
        { genCompPropStr },
        uiType
      );
      if (needWrapReadonly) {
        str = wrapReadonlyToken(str, formField);
      }
      if (needWrapItem) {
        str = wrapFormItemToken(str, formField);
      }
      return str;
    },
  };
}

function genSubFormStr(subFormField, formData, formRule, store) {
  const {
    wrapRowToken,
    wrapSubFormTableToken,
    wrapSubFormTableColumnToken,
    wrapGroupFormWrapToken,
  } = genTokenUtil(store.uiType);

  const {
    formKey,
    fieldList,
    genConfig: { subFormType },
  } = subFormField;
  let codeStr = "";
  // 多行子表单
  if (subFormType == "multiRow") {
    formData[subFormField.formKey] = [];
    // 表单模式
    const isFormField = store.wrapFormFieldToken;
    if (isFormField) {
      const subFormItem = {};
      for (const field of fieldList) {
        if (!isTableHelperColumn(field.label)) {
          subFormItem[field.formKey] = getFieldDefaultValue(field.type);
        }

        let fieldStr = formItemFactory(
          {
            ...field,
            formKey: `${subFormField.formKey}.\${$index}.${field.formKey}`,
          },
          store
        ).generator(true, false);

        fieldStr = wrapSubFormTableColumnToken(fieldStr, field);
        codeStr += fieldStr;
        if (Object.keys(field.rules).length > 0) {
          formRule[`${field.formKey}`] = genRules(field);
        }
      }
      formData[subFormField.formKey].push(subFormItem);
    } else {
      for (const field of fieldList) {
        codeStr += wrapSubFormTableColumnToken("", field, true);
      }
    }
    codeStr = wrapSubFormTableToken(codeStr, subFormField, !isFormField);
  } else {
    formData[subFormField.formKey] = {};
    let row = [];
    for (let index = 0; index < fieldList.length; index++) {
      const field = fieldList[index];
      const fieldStr = genFieldStr(
        {
          ...field,
          formKey: `${subFormField.formKey}.${field.formKey}`,
        },
        store
      );
      if (field.singleRow) {
        if (row.length > 0) {
          codeStr += wrapRowToken(row.join(""));
          row = [];
        }
        codeStr += wrapRowToken(fieldStr);
      } else {
        row.push(fieldStr);
        if (row.length === store.columnNum) {
          codeStr += wrapRowToken(row.join(""));
          row = [];
        }
      }
      if (Object.keys(field.rules).length > 0) {
        formRule[`${subFormField.formKey}.${field.formKey}`] = genRules(field);
      }
      formData[subFormField.formKey][field.formKey] = field.type.endsWith(
        "select"
      )
        ? undefined
        : "";
    }
    if (row.length > 0) {
      codeStr += wrapRowToken(row.join(""));
      row = [];
    }
  }
  if (formKey !== "default") {
    codeStr = wrapGroupFormWrapToken(codeStr, subFormField);
  }
  return codeStr;
}

function genFieldStr(formField, store) {
  const { wrapColToken, wrapFormItemToken, wrapFieldTextToken } = genTokenUtil(
    store.uiType
  );
  const isFormField = store.wrapFormFieldToken;
  if (isFormField) {
    return wrapColToken(formItemFactory(formField, store).generator());
  } else {
    return wrapColToken(
      wrapFormItemToken(wrapFieldTextToken(formField), formField)
    );
  }
}

export function genPlaceholder(formField) {
  return (
    formField.fiedlProps?.placeholder ??
    (formField.type.endsWith("select") ? "请选择" : "请输入") + formField.label
  );
}

export function genCompPropStr(field, globalConfig) {
  const { props } = field;
  const isVue3 = isVue3Version(globalConfig);
  let result = "";
  for (const key of Object.keys(props)) {
    const val = props[key];
    if (isObject(val) || isFunction(val)) {
      result += `:${key}='${JSON.stringify(val)} '`;
    } else {
      result += `${key}="${val}" `;
    }
  }
  let formKey = field.formKey;
  const formKeyArr = formKey.split(".");
  const isSubForm = formKeyArr.length > 2;
  if (isSubForm) {
    const formKeyArr = formKey.split(".");
    formKey = formKeyArr[formKeyArr.length - 1];
  }
  result += `v-model${isVue3 ? ":value" : ""}${
    ["input", "textarea"].includes(field.type) ? ".trim" : ""
  }="${isSubForm ? `row.${formKey}` : `formData.${formKey}`}" `;
  return result;
}

export function genRules(formField) {
  const { type, label, rules } = formField;
  const result = [];
  const placeholder = genPlaceholder(formField);
  for (const key of Object.keys(rules)) {
    if (key === "required" && rules[key]) {
      result.push({
        required: true,
        trigger: type.endsWith("select") ? "change" : "blur",
        message: placeholder,
      });
    } else if (key === "len" && rules[key] > 0) {
      result.push({
        min: 1,
        max: rules[key],
        trigger: type.endsWith("select") ? "change" : "blur",
        message: `${label}长度在1~${rules[key]}之间`,
      });
    }
  }
  return result;
}

// 根据字段列表，生成form template字符串、表单数据、表单验证规则、table column
function fieldList2codeData(store, fieldList) {
  const formData = {};
  const formRule = {};
  let result = "";
  let row = [];
  const { wrapRowToken, wrapGroupFormWrapToken } = genTokenUtil(store.uiType);
  for (let index = 0; index < fieldList.length; index++) {
    const field = fieldList[index];
    const { type, formKey } = field;
    if (type === "subForm") {
      if (row.length > 0) {
        result += wrapRowToken(row.join(""));
        row = [];
      }
      const fieldStr = genSubFormStr(field, formData, formRule, store);
      result += fieldStr;
    } else if (type === "groupForm") {
      if (row.length > 0) {
        result += wrapRowToken(row.join(""));
        row = [];
      }
      const { fieldList: groupFieldList } = field;
      let groupFormCode = "";
      for (let index = 0; index < groupFieldList.length; index++) {
        const groupField = groupFieldList[index];
        const fieldStr = genFieldStr(groupField, store);
        if (groupField.singleRow) {
          if (row.length > 0) {
            groupFormCode += wrapRowToken(row.join(""));
            row = [];
          }
          groupFormCode += wrapRowToken(fieldStr);
        } else {
          row.push(fieldStr);
          if (row.length === store.columnNum) {
            groupFormCode += wrapRowToken(row.join(""));
            row = [];
          }
        }
        if (Object.keys(groupField.rules).length > 0) {
          formRule[groupField.formKey] = genRules(groupField);
        }
        formData[groupField.formKey] = getFieldDefaultValue(groupField.type);
      }
      if (row.length > 0) {
        groupFormCode += wrapRowToken(row.join(""));
        row = [];
      }
      if (formKey !== "default") {
        result += wrapGroupFormWrapToken(groupFormCode, field);
      } else {
        result += groupFormCode;
      }
    }
  }
  return {
    formTemplate: result,
    formData,
    formRule,
  };
}

// 代码相关数据为字符串
function codeDataStringify(layoutConfig, formData, formRule, store) {
  const formDataStr = JSON.stringify(formData, (key, value) =>
    typeof value === "undefined" ? "%undefined%" : value
  ).replaceAll('"%undefined%"', undefined);

  const formRuleStr = JSON.stringify(formRule);

  const {
    formLayout: { labelWidth, ...restFormLayout },
    ...rest
  } = layoutConfig;
  let uiFormLayout = { formLayout: { ...restFormLayout } };
  if (store.uiType === "Element") {
    uiFormLayout.formLayout = {
      labelSuffix: ":",
      labelWidth: labelWidth + "px",
    };
  }
  const layoutConfigStr = JSON.stringify({ ...uiFormLayout, ...rest });
  return {
    layoutConfigStr,
    formDataStr,
    formRuleStr,
  };
}

function genFormFile(codeStrObj, fieldList, fileTemplate) {
  const { layoutConfigStr, formTemplate, formDataStr, formRuleStr } =
    codeStrObj;

  function visitField(fieldMap, fieldList) {
    for (const field of fieldList) {
      const { type, label, fieldList: subFieldList } = field;
      if (!isTableHelperColumn(label)) {
        if (type === "groupForm") {
          visitField(fieldMap, subFieldList);
        } else {
          fieldMap.push(genFieldMapField(field));
        }
      }
    }
  }

  const fieldMap = [];

  visitField(fieldMap, fieldList);

  let codeStr = fileTemplate
    .replace("`%formCode%`", formTemplate)
    .replace("`%layoutConfigCode%`", layoutConfigStr)
    .replace("`%formDataCode%`", formDataStr)
    .replace("`%formRuleCode%`", formRuleStr);

  return {
    "App.vue": codeStr + `\r/** %fieldMap=${JSON.stringify(fieldMap)}% */`,
  };
}

export async function genCode(globalConfig, fieldList) {
  const store = useFormStore();

  fieldConfig = getFieldConfig(store.uiType);

  // 全局字段列表，生成模版代码、表单代码、表单验证代码
  const { formTemplate, formData, formRule } = fieldList2codeData(
    store,
    fieldList
  );

  const codeStrObj = codeDataStringify(
    globalConfig.layoutConfig,
    formData,
    formRule,
    store
  );

  const fileTemplate = await import(
    `../../template/form/${store.templateFile}.vue?raw`
  );

  const codeFile = genFormFile(
    { formTemplate, ...codeStrObj },
    fieldList,
    fileTemplate.default
  );

  return codeFile;
}
